home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Gekkan Dennou Club 140
/
Gekkan Dennou Club - 2000.1 Vol. 140 (Japan).7z
/
Gekkan Dennou Club - 2000.1 Vol. 140 (Japan) (Track 1).bin
/
tools
/
dshell
/
dsh333bs.lzh
/
sort.c
< prev
next >
Wrap
C/C++ Source or Header
|
1999-12-05
|
68KB
|
3,058 lines
/*
dshell v3
テキストファイルを内部バッファへ展開
*/
#include "dsh.h"
static uchar defKinsokuChrs[] =
"、。」』?!)}〕]〉》】”’,."
"ぁぃぅぇぉっゃゅょァィゥェォッャュョ";
static uchar *kinsokuChrs;
static uchar Kinw[3];
#define nextLine(x) ({ \
uchar *_p = (x); \
asm( \
"0:\n" \
" move.b (%0)+,d0\n" \
" beq.s 1f\n" \
" cmpi.b #$0a,d0\n" \
" beq.s 2f\n" \
" cmpi.b #$1a,d0\n" \
" bne.s 0b\n" \
"1:\n" \
" subq.l #1,%0\n" \
"2:\n" \
: "=a"(_p) : "0"(_p) : "d0"); \
_p; \
})
#define skipNulLine(x) ({ \
uchar *_p = (x), _c; \
while ((_c = *_p++) == '\r' || _c == '\n') \
; \
_p - 1; \
}) \
#define skipBlank(x) ({ \
uchar *_p = (x), _c; \
while ((_c = *_p++) == '\x20' || _c == '\t') \
; \
_p - 1; \
}) \
#define stpcpy(p, q) ({ \
uchar *_p = (p); \
const uchar *_q = (q); \
while (*_p++ = *_q++) \
; \
_p - 1; \
}) \
/*
書式指定
*/
typedef struct form {
struct form *last;
short width; // 字詰め幅
short lmargin; // 左余白
short indent; // インデント
short lspace; // 行ごとに挿入する空行の数
short tabWidth; // TAB 幅 (特に 0...8桁ごと)
short boxMargin; // %box 内の左右マージン
short cutMargin; // %CUT 回り込み時のマージン
uchar eolChr; // 行末を表す文字
uchar ctrlChr; // コマンド先頭文字
uchar closeChr; // コマンド閉じ
uchar closeChr2; // \n を %V%W の終端と認識するなら \n, でなければ \0
uchar escChr; // エスケープ文字
uchar breakChr; // 論理行末
uchar wrapFlag; // 字詰めの有無
uchar blockAlignMode; // 現ブロックの行揃えモード
signed char fillMode; // 追い込みの有無とモード (0...なし, >0...文字単位, <0...語単位)
signed char fillModeDef; // 追い込み ON 時のモード
uchar refChr; // 文字列置換先頭文字
} FORM;
static const FORM formInit = {
NULL, // last
0, // width
0, // lmargin
0, // indent
1 - 1, // lspace
8, // tabWidth
2, // boxMargin
2, // cutMargin
'\n', // eolChr
'%', // ctrlChr
'\x18', // closeChr
'\n', // closeChr2
'\0', // escChr
'/', // breakChr
TRUE, // wrapFlag
0, // blockAlignMode
0, // fillMode
-1, // fillModeDef
0, // refChr
};
#define Width (f->width)
#define Lmargin (f->lmargin)
#define Indent (f->indent)
#define Lspace (f->lspace)
#define TabWidth (f->tabWidth)
#define BoxMargin (f->boxMargin)
#define CutMargin (f->cutMargin)
#define EolChr (f->eolChr)
#define CtrlChr (f->ctrlChr)
#define CloseChr (f->closeChr)
#define CloseChr2 (f->closeChr2)
#define EscChr (f->escChr)
#define BreakChr (f->breakChr)
#define WrapFlag (f->wrapFlag)
#define BlockAlignMode (f->blockAlignMode)
#define FillMode (f->fillMode)
#define FillModeDef (f->fillModeDef)
#define RefChr (f->refChr)
/*
書式指定コマンド
*/
enum {
RETRY_CMD,
RESET_CMD,
WIDTH_CMD,
LMARGIN_CMD,
INDENT_CMD,
TINDENT_CMD,
LSPACE_CMD,
TAB_CMD,
WRAP_CMD,
FILL_CMD,
WORDWRAP_CMD,
ALIGN_CMD,
SPACE_CMD,
HRULE_CMD,
BOX_CMD,
ENDBOX_CMD,
BOXMARGIN_CMD,
CUTMARGIN_CMD,
CUTFLUSH_CMD,
CUT_CMD,
CTRLCHAR_CMD,
ESCCHAR_CMD,
BREAKCHAR_CMD,
SEPCHAR_CMD,
REFCHAR_CMD,
HANGCHAR_CMD,
SET_CMD,
INC_CMD,
CONST_CMD,
FONT_CMD,
ENDFONT_CMD,
TEXTCOLOR_CMD,
BGCOLOR_CMD,
BGCUT_CMD,
PUSH_CMD,
POP_CMD,
MACRO_CMD,
IF_CMD,
ELIF_CMD,
ELSE_CMD,
ENDIF_CMD,
INCLUDE_CMD,
END_CMD,
MENU_CMD,
LABEL_CMD,
NCMDS,
};
#define v3_31 1
#define v3_32 2
#define v3_33 3
#define cfBREAK 0x01 // 強制 BREAK
#define cfNBREAK 0x00
static const struct {
uchar version;
uchar flag;
uchar *name;
} commandTable[] = {
{ 0, 0, NULL, },
{ v3_31, cfBREAK, "reset", },
{ v3_31, cfBREAK, "width", },
{ v3_31, cfBREAK, "left-margin", },
{ v3_31, cfBREAK, "indent", },
{ v3_31, cfBREAK, "temp-indent", },
{ v3_31, cfBREAK, "line-space", },
{ v3_31, cfBREAK, "tab-width", },
{ v3_31, cfBREAK, "wrap", },
{ v3_31, cfBREAK, "fill", },
{ v3_31, cfBREAK, "word-wrap", },
{ v3_31, cfBREAK, "align", },
{ v3_31, cfNBREAK, "space", },
{ v3_31, cfBREAK, "h-rule", },
{ v3_32, cfBREAK, "box", },
{ v3_32, cfBREAK, "endbox", },
{ v3_32, cfBREAK, "box-margin", },
{ v3_32, cfBREAK, "cut-margin", },
{ v3_32, cfNBREAK, "cut-flush", },
{ v3_32, cfNBREAK, "cut", },
{ v3_31, cfBREAK, "ctrl-char", },
{ v3_31, cfBREAK, "esc-char", },
{ v3_31, cfBREAK, "break-char", },
{ v3_31, cfBREAK, "sep-char", },
{ v3_32, cfBREAK, "ref-char", },
{ v3_31, cfBREAK, "hang-char", },
{ v3_32, cfNBREAK, "set", },
{ v3_32, cfNBREAK, "inc", },
{ v3_32, cfNBREAK, "const", },
{ v3_32, cfNBREAK, "font", },
{ v3_32, cfNBREAK, "endfont", },
{ v3_31, cfBREAK, "text-color", },
{ v3_31, cfBREAK, "bg-color", },
{ v3_31, cfBREAK, "bg-cut", },
{ v3_31, cfBREAK, "push", },
{ v3_31, cfBREAK, "pop", },
{ v3_31, cfBREAK, "macro", },
{ v3_32, cfNBREAK, "if", },
{ v3_32, cfNBREAK, "elif", },
{ v3_32, cfNBREAK, "else", },
{ v3_32, cfNBREAK, "endif", },
{ v3_32, cfNBREAK, "include", },
{ v3_31, cfBREAK, "end", },
{ v3_33, cfBREAK, "menu", },
{ v3_33, cfBREAK, "label", },
};
/*
マクロ/変数定義
*/
typedef struct macro {
struct macro *next;
uchar *contents;
uchar name[0];
} MACRO, VAR;
static VAR *varListHead = NULL;
typedef struct args {
struct args *prev;
VAR *arg[10];
} ARGS;
static ARGS *macroArgs;
#define TEXTSTACK_MAX 32 // マクロネスト最大
typedef struct {
uchar *text;
char flag;
} TEXTSTACK;
static TEXTSTACK textStack[TEXTSTACK_MAX + 2], *tsp;
enum {
inCONST = 0x80, // &~; の処理中
inMACRO = 0x01, // 引数付きマクロの処理中
inMACRO_NA = 0x02, // 引数無しマクロの処理中
inINCLUDE = 0x04, // %include の処理中
};
static int getCommand(uchar *, uchar);
static short getNum(uchar *, short);
static short getNum2(uchar *, short, short, short);
static ushort getRGB(uchar *, ushort);
static uchar getEscSeq(uchar *);
static uchar *getMacro(MACRO *, uchar *, uchar);
static uchar *getIndentStr(uchar *, short);
static uchar *getSysVar(uchar *);
static uchar *getHRule(uchar *, uchar *, short);
static uchar refVar(uchar *, const FORM *f);
static VAR *getVar(const uchar *);
static int setVar(const uchar *, const uchar *);
static int incVar(const uchar *);
static int setSysVar(const uchar *, const uchar *);
static uchar *expandCommand(uchar *, uchar *, const FORM *, uchar);
static uchar *expandMacroArg(ARGS *, uchar *, uchar *, const FORM *);
static void freeMacroArg(void);
static int skipIfBlock(const uchar *, uchar, uchar);
static int sort_job24(uchar *, uchar *, short, short, const FORM *, uchar *);
static int sort_job12(uchar *, uchar *, short, short, const FORM *, uchar *);
static int sort_job_12_24(uchar *, uchar *, short, short, const FORM *, uchar *, uchar, uchar);
static int getTypeLine(uchar *, uchar *, uchar *, const FORM *);
static int getMenuLine(uchar *, uchar *, uchar *, const FORM *);
static uchar *envSubst(uchar *, uchar *, const FORM *);
static uchar **moveLhp(uchar **, uchar **, int);
static int align(uchar *, uchar *, short, short, uchar);
static short adjustColumn(short, uchar);
static uchar *insertCut(uchar *, short, uchar, uchar, uchar);
static uchar *setColor(uchar *, uchar);
extern int evalCond(uchar *);
/*
文字幅等の調整
ptr 修正後のポインタ(表示用に整理し終えたテキスト)
lhp0 修正前のポインタ(丸読みした状態のテキスト)
=行ポインタ仮テーブル先頭アドレス(尻尾から)
fname ファイル名
filesize ファイルサイズ
noCtrlFlag 非0...制御文字列無効
整理後のテキスト+行ポインタテーブル末尾を返す
エラーなら NULL
*/
static uchar *PTR, *PTR2;
static uchar version;
void *
sort(uchar *ptr, uchar **lhp0, uchar *fname, int filesize, uchar noCtrlFlag, void *menuId)
{
#define LINENO (lhp0 - tlhp)
short column;
uchar **tlhp; /* 行ポインタ仮テーブル先頭へのポインタ */
uchar c = '\n';
uchar *ptr2, *optr2, *lineHead, *wordHead;
uchar *alignPtr = NULL;
uchar *indentPtr = NULL;
short maxColumn; // 現処理行の字詰め幅
short alignColumn = 0;
uchar ctrlChr;
uchar alignMode; // 現処理行の行揃えモード
uchar tempCloseChr;
uchar bolFlag = TRUE;
uchar bolFlag2;
signed char fontSize = 0; // 現在のフォントサイズ (0...16,1...24,-1...12)
FORM form, *f = &form;
short defWidth = -1;
short defLmargin = -1;
short defLspace = -1 - 1;
short defTabWidth = -1;
short defBoxMargin = -1;
short defCutMargin = -1;
short tempIndent = -128;
short lineSpace, leftMargin;
MACRO *macroListHead = NULL;
uchar boxStr[20];
uchar endBoxChars[6+1];
uchar *boxPtr = NULL;
#define FONTHIS_MAX 32
uchar fontHis[FONTHIS_MAX + 1], *fontP;
/* cut ↓ */
int cutNo = -2;
uchar cutLineNo = 0;
uchar cutLineNoMax = 0;
short cutWidth = 0;
struct NAMECKBUF docPath;
uchar cutID[5 + 1];
signed char cutAlignMode = 0;
signed char cutBottomSpace = FALSE;
short cutColumn = 0;
uchar cutColor = 3;
NAMECK(fname, &docPath); // '+'オプション時用のパスを得る
/* cut ↑ */
*f = formInit;
Width = CWIDTH - 2;
kinsokuChrs = defKinsokuChrs;
optr2 = ptr2 = (uchar *)lhp0; // ベタテキスト先頭
tlhp = lhp0;
tsp = textStack + TEXTSTACK_MAX + 1;
tsp->text = NULL;
tsp->flag = 0;
curColor = 3; // 表示色
fontP = fontHis;
*fontP = '\0';
boxStr[0] = '\0';
version = 0;
if (noCtrlFlag) {
CtrlChr = '\0';
} else {
uchar *p;
if (strnEqu(ptr2, "%DSHELL", 7)
&& (ptr2[7] == '\x20' || ptr2[7] == '\t')
&& strnEqu(p = skipBlank(ptr2 + 8), "v3.3", 4)
&& (p[4] == '1' || p[4] == '2' || p[4] == '3')) {
int n;
FillMode--; // %fill on, %word-wrap on
EolChr = BreakChr; //
CloseChr2 = '\0'; // %V%W は LF で閉じない
n = dinstr(defKinsokuChrs, "ぁ");
if (--n > 0) {
defKinsokuChrs[n] = '\0'; //“小さなかな”を行頭禁則対象から外す
if ((kinsokuChrs = strdup(defKinsokuChrs)) == NULL)
goto HEAP_ERROR;
defKinsokuChrs[n] = (uchar)((L'ぁ') >> 8);
}
version = v3_31;
if (p[4] >= '2') {
version++; // v3.32 では
EscChr = '\\'; // %esc-char \ (←う、// 以降でも行末に \ があると行接続が効いちゃうのね...)
CloseChr = ';'; // %sep-char ;
RefChr = '&'; // %ref-char &
if (p[4] >= '3')
version++;
}
ptr2 = nextLine(ptr2);
}
}
/*
! 一番でかいループ
*/
for (;;) { /* 各行処理のループ */
/*
作業進度スケール
*/
if (filesize > 4*1024 && tsp->flag == 0) {
short i, j;
short tbf[10];
static short oldj = -1;
j = (ptr2 - optr2) * 10 / filesize;
if (j != oldj) {
for (i = 0; i < j; i++) {
tbf[i] = L'■';
}
for (; i < 9; i++) {
tbf[i] = L'□';
}
tbf[9] = 0;
w_mes(2, (char *)tbf);
oldj = j;
}
}
p_time(0); /* 時計の時間表示 */
if ((void *)ptr > (void *)tlhp)
goto ERROR;
*--tlhp = ptr;
ctrlChr = CtrlChr;
LINE_RETRY:
if (EolChr != '\n')
ptr2 = skipNulLine(ptr2);
column = 0;
leftMargin = Lmargin;
maxColumn = Width + Lmargin;
if (boxStr[0] != '\0') {
short n = boxStr[2] - NUM_BIAS + 2;
maxColumn = (boxStr[6] - NUM_BIAS) + n - BoxMargin;
n += BoxMargin;
if (n > leftMargin)
leftMargin = n;
}
if (cutAlignMode < 0 || cutBottomSpace < 0) {
if (cutColumn >= leftMargin)
leftMargin = cutColumn + cutWidth + CutMargin;
}
if (cutAlignMode > 0 || cutBottomSpace > 0) {
if (cutColumn < maxColumn)
maxColumn = cutColumn - CutMargin;
}
cutBottomSpace = 0;
lineSpace = Lspace;
alignMode = BlockAlignMode;
if (!WrapFlag)
maxColumn = CWIDTH;
tempCloseChr = EolChr;
bolFlag2 = TRUE;
if (bolFlag) {
if (*ptr2 == (uchar)(L'━' >> 8) && *(ptr2 + 1) == (uchar)(L'━')) {
*ptr++ = CTRL_CHAR;
*ptr++ = HR_CHAR;
} else if (ctrlChr != '\0') {
if (*ptr2 == '\x18' && FillMode == 0) {
/*
行頭が^Xの時、改行があるかテキストが終るまで強制的に1行に表示する。
(エラーチェックなど一切しないので、使用の際は注意のこと)
*/
ptr2++;
maxColumn = SHRT_MAX; // 十分大きな値
ctrlChr = '\0';
} else {
/*
行頭の'◎'
*/
if (*ptr2 == (uchar)(L'◎' >> 8) && *(ptr2 + 1) == (uchar)(L'◎')) {
*ptr++ = CTRL_CHAR;
*ptr++ = DUMMY_CHAR; // 仮にダミーの内部コード
ptr2 += 2;
column += 2;
bolFlag2 = FALSE;
}
/*
行頭の ^[[m (埋め込みのブレイクポイント)
*/
if (*ptr2 == '\x1b' && *(ptr2 + 1) == '[' && *(ptr2 + 2) == 'm') {
*ptr++ = *ptr2++;
*ptr++ = *ptr2++;
*ptr++ = *ptr2++;
curColor = 3;
}
}
}
}
/*
前行のフォントを引き継ぐ
*/
if (fontHis[0] != 0) {
*ptr++ = CTRL_CHAR;
*ptr++ = FONT_CHAR;
ptr = stpcpy(ptr, fontHis);
*ptr++ = NORM_CHAR;
}
/*
%box
*/
if (boxStr[0] != '\0') {
boxPtr = ptr;
ptr = stpcpy(ptr, boxStr);
}
/*
インデント
*/
indentPtr = ptr;
alignPtr = NULL;
if (column == 0) {
switch (alignMode) {
case '=':
case '>':
column = alignColumn = leftMargin;
*ptr++ = '\x1b';
*ptr++ = '[';
*ptr++ = (column / 10) + '0';
*ptr++ = (column % 10) + '0';
*ptr++ = 'C';
alignPtr = ptr;
break;
default:
if (tempIndent > -128) {
column = tempIndent;
tempIndent = -128;
} else {
column = leftMargin + Indent;
}
ptr = getIndentStr(ptr, column);
break;
}
}
/*
前行の文字表示属性を引き継ぐ
*/
if (curColor != 3)
ptr = setColor(ptr, curColor);
lineHead = ptr; // ptr == lineHead の間は空行として認識する
if (!bolFlag2)
lineHead = NULL;
/*
前行のフォントサイズを引き継ぐ
*/
FONTSIZE_RETRY:
wordHead = ptr2;
if (fontSize != 0) {
uchar contFlag = FALSE;
if (fontSize > 0)
column = sort_job24(ptr, ptr2, column, maxColumn, f, &contFlag);
else
column = sort_job12(ptr, ptr2, column, maxColumn, f, &contFlag);
ptr = PTR;
ptr2 = PTR2;
if (tsp->flag < 0)
ctrlChr = '\0';
wordHead = ptr2;
if (contFlag && WrapFlag) {
bolFlag = (contFlag > TRUE);
goto ENCOUNT_EOL;
}
fontSize = 0;
}
/*
! 1行内の処理
*/
while (column < maxColumn) { /* 一行内処理のループ */
CHAR_RETRY:
c = *ptr2++; /* 1バイト読み込み */
CTRL_RETRY:
if (c == '\0' || c == '\x1a') {
c = '\0';
if (tsp->text != NULL) {
wordHead = ptr2 = tsp->text;
if (tsp->flag & inMACRO)
freeMacroArg();
tsp++;
ctrlChr = CtrlChr;
if (ptr != lineHead)
continue;
ptr = *tlhp;
goto LINE_RETRY;
}
if (ptr != lineHead) {
ptr2--;
bolFlag = TRUE;
goto ENCOUNT_EOL;
}
ptr = *tlhp++;
goto ENCOUNT_EOF;
} else if (c == EolChr) {
bolFlag = TRUE;
goto ENCOUNT_EOL;
} else if (c == tempCloseChr) {
if (alignPtr >= *tlhp) {
column += align(ptr, alignPtr, maxColumn - (column - alignColumn), leftMargin, alignMode);
ptr = PTR;
alignPtr = NULL;
}
tempCloseChr = EolChr;
alignMode = BlockAlignMode;
if (alignMode) {
if (column > 0)
*ptr++ = '\r';
*ptr++ = '\x1b';
*ptr++ = '[';
*ptr++ = (column / 10) + '0';
*ptr++ = (column % 10) + '0';
*ptr++ = 'C';
alignPtr = ptr;
alignColumn = column;
}
continue;
} else if (iscntrl(c)) {
switch (c) {
case '\t':
if (TabWidth == 8) {
*ptr++ = c;
column += 8;
column &= -8;
} else {
short n;
n = column + TabWidth;
n -= (n % TabWidth) + column;
while (--n >= 0)
*ptr++ = '\f';
}
continue;
case '\b':
if (column == 0)
continue;
*ptr++ = c;
column--;
continue;
case '\f':
break;
case '\x1b':
{
int i = isEscSeq(ptr2);
if (i > 0) {
if (ptr2[i - 1] == 'm' && ptr == lineHead)
lineHead += i + 1;
*ptr++ = c;
while (--i >= 0)
*ptr++ = *ptr2++;
if (*(ptr - 1) == 'C' || *(ptr - 1) == 'D')
column = adjustColumn(column, *(ptr - 1) == 'C');
wordHead = ptr2;
}
}
continue;
case '\n':
if (ptr != lineHead && isalnum(*ptr2) && FillMode < 0) {
c = '\x20'; // 次行々頭の英数字列と分離
break;
}
continue;
default:
continue;
}
} else if (c == EscChr) {
c = getEscSeq(ptr2);
ptr2 = PTR2;
if (c == '\r') {
if (column > 0) {
*ptr++ = c;
column = 0;
}
continue;
}
if (iscntrl(c))
goto CTRL_RETRY;
} else if (c == ctrlChr) {
/*
! 制御文字を呼び出したか?
*/
char command;
int n;
if (ptr2[0] == 'V' && ptr2[1] == ctrlChr && ptr2[2] == 'W') {
/*
!! 24ドット処理
*/
ptr2 += 3; // skip "V%W"
fontSize++;
goto FONTSIZE_RETRY;
} else if (ptr2[0] == 'v' && ptr2[1] == ctrlChr && ptr2[2] == 'w') {
/*
12ドット処理
*/
ptr2 += 3; // skip "v%w"
fontSize--;
goto FONTSIZE_RETRY;
} else if (ptr2[0] == 'C' && ptr2[1] == 'U' && ptr2[2] == 'T') {
/*
!! CUT処理
*/
uchar *pbak = ptr2;
ptr2 += 3; // skip "CUT"
if (*ptr2 == ':') { // カットファイル名指定あり
uchar *tail = ptr2; // 次処理位置
struct NAMECKBUF cutFname; // カットファイル名一時格納先
cutNo = getCutNo(ptr2 + 1, (char *)&docPath, &cutFname, &tail, CloseChr);
if (cutNo >= 0 && cut[cutNo].fname == NULL) {
/*
カットファイル名を
整理後テキストの途中 (現在処理行の直前) に移動/挿入する
*/
uchar *p, *q;
q = ptr;
n = strlen((char *)&cutFname) + 1;
indentPtr += n;
alignPtr += n;
lineHead += n;
ptr += n;
p = ptr;
n = q - *tlhp;
while (--n >= 0)
*--p = *--q;
cut[cutNo].fname = strcpy(q, (char *)&cutFname);
*tlhp = p;
}
ptr2 = tail;
if (cutNo >= 0) {
if (cut[cutNo].type < 0) {
cutNo = -1;
} else {
cutLineNo = NUM_BIAS;
cutLineNoMax = NUM_BIAS + lineCount(cut[cutNo].y);
cutWidth = byteCount(cut[cutNo].x);
}
}
}
cutAlignMode = 0;
if (cutNo >= 0) { /* "CUT:"より下の行だった時だけCUT表示処理対象とみなす */
if (version == 0) { // 激電の MOKUJI.DOC (他にもあるかも) に見られるゴミスペース対策...
uchar *p, cc;
for (p = ptr2; (cc = *p++) == '\x20' || cc == '\t' || cc == 0x81 && *p++ == 0x40;)
;
p--;
if (*p == '\r')
p++;
if (*p == '\0' || *p == '\n' || *p == '\x1a')
ptr2 = p;
}
if ((cut[cutNo].flag & (cutLEFT | cutRIGHT)) && Width < cutWidth + 2) {
cut[cutNo].flag &= ~(cutLEFT | cutRIGHT);
cut[cutNo].flag |= cutDUP;
}
if (cut[cutNo].flag & cutLEFT) {
cut[cutNo].flag &= ~(cutLEFT | cutRIGHT | cutDUP);
cutAlignMode--;
cutColumn = Lmargin;
if (boxStr[0] != '\0')
cutColumn += 2 + BoxMargin;
cutColor = curColor;
if (ptr != lineHead)
goto ENCOUNT_EOL;
ptr = *tlhp;
goto LINE_RETRY;
} else if (cut[cutNo].flag & cutRIGHT) {
cut[cutNo].flag &= ~(cutLEFT | cutRIGHT | cutDUP);
cutAlignMode++;
cutColumn = Lmargin + Width - cutWidth;
if (boxStr[0] != '\0')
cutColumn -= 2 + BoxMargin;
if (cutColumn < 0)
cutColumn = 0;
maxColumn = cutColumn - CutMargin;
if (maxColumn < 0)
maxColumn = 0; /////
cutColor = curColor;
if (ptr != lineHead)
goto ENCOUNT_EOL;
continue;
}
*ptr++ = CTRL_CHAR;
*ptr++ = CUT_CHAR;
*ptr++ = (cutNo >> 6) + NUM_BIAS;
*ptr++ = (cutNo & (64 - 1)) + NUM_BIAS;
*ptr++ = cutLineNo++;
if (cut[cutNo].flag & cutDUP) {
uchar *p = ptr - 5, *q = cutID;
*q++ = *p++;
*q++ = *p++;
*q++ = *p++;
*q++ = *p++;
*q++ = *p++;
*q = '\0';
}
*ptr++ = column + NUM_BIAS;
column += cutWidth;
if (cutLineNo >= cutLineNoMax)
cutNo = -1;
wordHead = ptr2;
continue;
} else {
if (version == 0 && cutNo >= -1 || *(pbak + 3) == ':')
continue;
ptr2 = pbak; // 'CUT' の頭に戻して通常文字列扱い
if (tsp > textStack + 1)
goto CHK_MACRO;
}
} else if (version > 0 && *(ptr2 - 2) == '\n'
&& (command = getCommand(ptr2, lineHead == ptr)) >= 0) {
/*
書式指定コマンド
*/
uchar *pp;
static uchar endBoxComStr[] = "\n%endbox";
if (command == BOX_CMD && boxStr[0] != '\0') {
(--tsp)->text = --ptr2;
tsp->flag = inMACRO_NA;
wordHead = ptr2 = endBoxComStr + 1;
*ptr2 = CtrlChr;
ptr = *tlhp;
tempIndent = boxStr[2] - NUM_BIAS;
goto LINE_RETRY;
}
if (command == RETRY_CMD) {
ptr2--;
bolFlag = TRUE;
goto ENCOUNT_EOL;
}
ptr2 = expandCommand(pp = ptr, PTR2, f, FALSE);
switch (command) {
case RESET_CMD:
if ((Lmargin = defLmargin) < 0)
Lmargin = 0;
if ((Width = defWidth) < 0)
Width = CWIDTH - 2 - Lmargin;
Indent = 0;
WrapFlag = TRUE;
FillMode = FillModeDef;
EolChr = BreakChr;
BlockAlignMode = 0;
if ((Lspace = defLspace) < 0)
Lspace = 0;
if ((TabWidth = defTabWidth) < 0)
TabWidth = 8;
if ((BoxMargin = defBoxMargin) < 0)
BoxMargin = 0;
if ((CutMargin = defCutMargin) < 0)
CutMargin = 0;
tempIndent = -128;
break;
case WIDTH_CMD:
n = getNum2(pp, Width, defWidth, CWIDTH - 2 - Lmargin);
if (n - Indent >= 3 && n + Lmargin <= CWIDTH)
Width = n;
if (defWidth < 0)
defWidth = Width;
break;
case LMARGIN_CMD:
if (*pp == '=')
n = (CWIDTH - Width) / 2;
else if (*pp == '>')
n = CWIDTH - Width;
else if (*pp == '<')
n = 0;
else
n = getNum2(pp, Lmargin, defLmargin, 0);
if (n >= 0 && n + Width <= CWIDTH)
Lmargin = n;
if (defLmargin < 0)
defLmargin = Lmargin;
break;
case INDENT_CMD:
n = getNum(pp, Indent);
if (n < 0)
n = 0;
if (Width - n >= 3)
Indent = n;
break;
case TINDENT_CMD:
n = getNum(pp, Indent);
n += Lmargin;
if (n >= 0)
tempIndent = n;
break;
case WRAP_CMD:
WrapFlag = (strnEqu(pp, "on", 2));
break;
case FILL_CMD:
FillMode = 0;
EolChr = '\n';
if (strnEqu(pp, "on", 2))
FillMode = FillModeDef;
if (FillMode)
EolChr = BreakChr;
break;
case WORDWRAP_CMD:
FillModeDef = 1;
if (strnEqu(pp, "on", 2))
FillModeDef--;
if (FillMode)
FillMode = FillModeDef;
break;
case ALIGN_CMD:
if (strnEqu(pp, "center", 6))
BlockAlignMode = '=';
else if (strnEqu(pp, "right", 5))
BlockAlignMode = '>';
else
BlockAlignMode = 0;
break;
case LSPACE_CMD:
n = getNum2(pp, Lspace + 1, defLspace + 1, 1);
if (n < 1)
n = 1;
Lspace = n - 1;
if (defLspace < 0)
defLspace = Lspace;
break;
case TAB_CMD:
n = TabWidth;
n = getNum2(pp, n, defTabWidth, 8);
if (n < 1)
n = 1;
TabWidth = n;
if (defTabWidth < 0)
defTabWidth = TabWidth;
break;
case SPACE_CMD:
n = 1;
if (*pp != '\n')
n = getNum(pp, 1);
if (n < 0)
continue;
lineSpace = n;
if (ptr == lineHead)
lineSpace--;
bolFlag = TRUE;
goto ENCOUNT_EOL;
case HRULE_CMD:
{
uchar *p, *q;
int n;
p = indentPtr;
ptr = getIndentStr(p, leftMargin);
ptr = getHRule(ptr, pp, maxColumn - leftMargin);
if (*p++ == (uchar)(L'━' >> 8) && *p == (uchar)(L'━')) {
n = ptr - *tlhp;
q = ptr;
ptr += 2;
p = ptr;
while (--n >= 0)
*--p = *--q;
*--p = HR_CHAR;
*--p = CTRL_CHAR;
}
alignPtr = NULL;
}
bolFlag = TRUE;
goto ENCOUNT_EOL;
case BOX_CMD:
if (maxColumn - column >= 6){
uchar buff[20], *p;
p = strcpy(buff, "┌─┐││└─┘");
for (n = 0; n < 8 && iskanji(*pp); n++) {
*p++ = *pp++;
*p++ = *pp++;
}
p = boxStr;
*p++ = CTRL_CHAR;
*p++ = BOX_CHAR;
*p++ = leftMargin + NUM_BIAS;
*p++ = (curColor & 3) + NUM_BIAS;
*p++ = buff[6];
*p++ = buff[7];
*p++ = ((maxColumn - leftMargin - 4) & -2) + NUM_BIAS;
*p++ = buff[8];
*p++ = buff[9];
*p = '\0';
strcpy(endBoxChars, buff + 10);
buff[6] = '\0';
ptr = getIndentStr(indentPtr, leftMargin);
ptr = getHRule(ptr, buff, maxColumn - leftMargin);
alignPtr = NULL;
bolFlag = TRUE;
leftMargin += 2;
goto ENCOUNT_EOL;
}
break;
case ENDBOX_CMD:
if (boxStr[0] != '\0') {
boxStr[0] = '\0';
ptr = getIndentStr(boxPtr, boxStr[2] - NUM_BIAS);
ptr = getHRule(ptr, endBoxChars, boxStr[6] - NUM_BIAS + 4);
alignPtr = NULL;
bolFlag = TRUE;
goto ENCOUNT_EOL;
}
break;
case BOXMARGIN_CMD:
n = getNum2(pp, BoxMargin, defBoxMargin, 2);
if (CWIDTH - n - n - 4 > 0)
BoxMargin = n;
if (defBoxMargin < 0)
defBoxMargin = BoxMargin;
break;
case CUTMARGIN_CMD:
n = getNum2(pp, CutMargin, defCutMargin, 2);
if (CWIDTH - n > 3)
CutMargin = n;
if (defCutMargin < 0)
defCutMargin = CutMargin;
break;
case CUTFLUSH_CMD:
if (cutAlignMode != 0 && cutNo >= 0 && cutLineNo < cutLineNoMax - 1) {
lineSpace = cutLineNoMax - cutLineNo - 1 + Lspace;
bolFlag = TRUE;
goto ENCOUNT_EOL;
}
continue;
case CUT_CMD:
{
uchar *qq, cc;
for (qq = pp; (cc = *qq++) > ' ' && cc != CloseChr;)
;
(--tsp)->text = ptr2;
tsp->flag = inMACRO_NA;
wordHead = ptr2 = qq + 256;
if ((void *)ptr2 + (qq - pp) > (void *)tlhp)
goto ERROR;
*--qq = '\0';
qq = stpcpy(ptr2, "%CUT:?-"); // 旧書式に変換
strcpy(qq, pp);
*ptr2 = CtrlChr;
}
continue;
case CTRLCHAR_CMD:
if (!iscntrl(*pp) && !iskanji1(*pp))
CtrlChr = ctrlChr = *pp++;
break;
case BREAKCHAR_CMD:
BreakChr = '\n';
if (!iscntrl(*pp) && !iskanji1(*pp))
BreakChr = *pp++;
if (FillMode)
EolChr = BreakChr;
break;
case ESCCHAR_CMD:
EscChr = '\0';
if (!iscntrl(*pp) && !iskanji1(*pp))
EscChr = *pp++;
break;
case SEPCHAR_CMD:
CloseChr = '\x18';
if (!iscntrl(*pp) && !iskanji1(*pp))
CloseChr = *pp++;
break;
case REFCHAR_CMD:
RefChr = '\0';
if (!iscntrl(*pp) && !iskanji1(*pp))
RefChr = *pp++;
break;
case HANGCHAR_CMD:
if (kinsokuChrs != defKinsokuChrs)
free(kinsokuChrs);
kinsokuChrs = pp;
while (iskanji(*pp))
pp += 2;
{
uchar cc = *pp;
*pp = '\0';
kinsokuChrs = strdup(kinsokuChrs);
*pp = cc;
}
if (kinsokuChrs == NULL)
goto HEAP_ERROR;
break;
case TEXTCOLOR_CMD:
tx_col[3] = getRGB(pp, tx_col[3]);
break;
case BGCOLOR_CMD:
gr_col[0] = getRGB(pp, gr_col[0]);
break;
case BGCUT_CMD:
if (*pp == '-') {
bgCut = NULL;
} else {
if ((pp = strdup(pp)) == NULL)
goto HEAP_ERROR;
ptr = *tlhp;
n = getCutNo(pp, (char *)&docPath, (struct NAMECKBUF *)ptr, NULL, CloseChr);
free(pp);
if (n >= 0) {
if (cut[n].fname == NULL) {
cut[n].fname = ptr;
while (*ptr++)
;
*tlhp = ptr;
}
bgCut = &cut[n];
}
}
break;
case PUSH_CMD:
{
FORM *ff = malloc(sizeof(FORM));
if (ff == NULL)
goto HEAP_ERROR;
*ff = *f;
ff->last = f;
f = ff;
}
break;
case POP_CMD:
if (f->last != NULL) {
FORM *ff = f;
f = f->last;
free(ff);
}
break;
case MACRO_CMD:
if ((tsp->flag & ~inINCLUDE) == 0) {
uchar *name, *contents, cc;
int l;
MACRO *macP;
name = pp;
while ((cc = *pp++) > '\x20'
&& cc != ctrlChr && cc != CloseChr && cc != '(')
;
*--pp = '\0';
if ((l = pp - name) == 0 || *ptr2 == '\0' || *ptr2 == '\x1a')
break;
contents = ptr2;
do {
ptr2 += strcspn(ptr2, "\n\x1a");
if (*ptr2 != '\n')
break;
ptr2++;
} while (*ptr2 != ctrlChr || !strnEqu(ptr2 + 1, "endm", 4) || *(ptr2 + 5) > '\x20');
macP = malloc(sizeof(MACRO) + (l + 1));
if (macP == NULL)
goto HEAP_ERROR;
macP->next = macroListHead;
macroListHead = macP;
macP->contents = contents;
strncpy(macP->name, name, l);
macP->name[l] = '\0';
*ptr2++ = '\x1a';
*ptr2++ = '\x1a';
ptr2 = nextLine(ptr2);
// if (EolChr != '\n')
// ptr2 = skipNulLine(ptr2);
}
break;
case SET_CMD:
{
uchar *name = pp, cc;
while ((cc = *pp++) > '\x20' && cc != '=' && cc != CloseChr)
;
*--pp = '\0';
if (pp++ == name || cc != '='
|| name[1] == '\0' && isdigit(name[0]))
break;
if (setVar(name, pp) < 0)
goto HEAP_ERROR;
}
if (lineHead == ptr)
break;
continue;
case INC_CMD:
{
uchar *name = pp, cc;
while ((cc = *pp++) > '\x20' && cc != '=' && cc != CloseChr)
;
*--pp = '\0';
if (pp != name && (name[1] != '\0' || !isdigit(name[0]))) {
if (incVar(name) < 0)
goto HEAP_ERROR;
}
}
if (lineHead == ptr)
break;
continue;
case CONST_CMD:
{
uchar *name = pp, cc;
while ((cc = *pp++) > '\x20' && cc != '=' && cc != CloseChr)
;
*--pp = '\0';
if (pp++ == name || cc != '=')
break;
if (setSysVar(name, pp) < 0)
goto HEAP_ERROR;
}
if (lineHead == ptr)
break;
continue;
case FONT_CMD:
if (fontP < fontHis + FONTHIS_MAX) {
int fontNo;
struct NAMECKBUF fontFname;
if ((pp = strdup(pp)) == NULL)
goto HEAP_ERROR;
fontNo = getFontNo(pp, (char *)&docPath, &fontFname, CloseChr);
free(pp);
if (fontNo >= 0) {
if (font16[fontNo].fname == NULL) {
uchar *p, *q;
q = ptr;
n = strlen((char *)&fontFname) + 1;
indentPtr += n;
alignPtr += n;
lineHead += n;
ptr += n;
p = ptr;
n = q - *tlhp;
while (--n >= 0)
*--p = *--q;
font16[fontNo].fname = strcpy(q, (char *)&fontFname);
*tlhp = p;
}
if (font16[fontNo].size > 0) {
*fontP++ = fontNo + NUM_BIAS;
*fontP = '\0';
if (ptr > lineHead) {
*ptr++ = CTRL_CHAR;
*ptr++ = FONT_CHAR;
*ptr++ = fontNo + NUM_BIAS;
*ptr++ = NORM_CHAR;
}
}
}
}
if (lineHead == ptr)
break;
continue;
case ENDFONT_CMD:
if (fontHis[0] != '\0') {
*--fontP = '\0';
if (ptr > lineHead) {
*ptr++ = CTRL_CHAR;
*ptr++ = EFONT_CHAR;
}
}
if (lineHead == ptr)
break;
continue;
case IF_CMD:
while (evalCond(pp) <= 0) {
if (!skipIfBlock(ptr2, CtrlChr, TRUE)) {
ptr2 = PTR2;
if (EolChr != '\n')
ptr2 = skipNulLine(ptr2);
break;
}
ptr2 = expandCommand(pp, PTR2, f, FALSE);
}
continue;
case ELIF_CMD:
case ELSE_CMD:
skipIfBlock(ptr2, CtrlChr, FALSE);
ptr2 = PTR2;
if (EolChr != '\n')
ptr2 = skipNulLine(ptr2);
continue;
case ENDIF_CMD:
continue;
case INCLUDE_CMD:
{
FILE *fp;
uchar *fname = pp;
uchar temp[256];
uchar **p1, **p2;
int m;
if (tsp <= textStack + 1) {
INCLUDE_ERROR:
for (pp = "*ERROR: include"; *ptr++ = *pp++;)
;
goto ENCOUNT_EOL0;
}
while (*pp++ > '\x20')
;
*--pp = '\0';
if (pp - fname == 0 || pp - fname > 90)
goto INCLUDE_ERROR;
if (*fname == '+') {
strcpy(temp, (char *)&docPath);
fname = strcat(temp, fname);
}
fp = fopen(fname, "rb");
if (fp == NULL || (n = dfilelength(fileno(fp))) < 0)
goto INCLUDE_ERROR;
if (n == 0) {
fclose(fp);
break;
}
p1 = ((void *)tlhp) - ((n + 3 + 3) & -4);
if ((uchar *)p1 < ptr)
goto ERROR;
p2 = tlhp;
m = lhp0 - tlhp;
tlhp = p1;
while (--m >= 0)
*p1++ = *p2++;
lhp0 = p1;
pp = (uchar *)p1;
*pp++ = '\n';
m = fread(pp, sizeof(char), n, fp);
fclose(fp);
if (m != n)
goto INCLUDE_ERROR;
*(pp + n) = '\0';
*(pp + n + 1) = '\0';
(--tsp)->text = ptr2;
tsp->flag = inINCLUDE;
ptr2 = pp;
if (EolChr != '\n')
ptr2 = skipNulLine(ptr2);
wordHead = ptr2;
}
if (ptr != lineHead)
continue;
break;
case END_CMD:
ptr = *tlhp++;
goto ENCOUNT_EOF;
case MENU_CMD:
ptr = *tlhp;
while (*ptr2 != '\0' && *ptr2 != '\x1a') {
if (*ptr2 == ctrlChr
&& strnEqu(ptr2 + 1, "endmenu", 7)
&& *(ptr2 + 8) <= '\x20') {
ptr2 = nextLine(ptr2);
break;
}
if (getMenuLine(ptr, ptr2, (uchar *)tlhp, f) < 0)
goto ERROR;
if (addMenuItem(menuId, ptr) < 0)
goto HEAP_ERROR;
ptr = PTR;
ptr2 = PTR2;
}
*tlhp = ptr;
bolFlag = TRUE;
goto LINE_RETRY;
case LABEL_CMD:
ptr = *tlhp;
bolFlag = TRUE;
goto LINE_RETRY;
}
ptr = *tlhp;
goto LINE_RETRY;
} else if (version > 0 && *ptr2 == '-' && *(ptr2 + 1) == '-') {
/*
ブロックコメント (%-- ~ --%)
*/
for (;;) {
ptr2 += strcspn(ptr2, "-\x1a");
if (*ptr2 != '-')
break;
if (*++ptr2 == '-'
&& (*(ptr2 + 1) == ctrlChr || *(ptr2 + 1) == CloseChr)) {
ptr2 += 2;
break;
}
}
continue;
} else if (version > 0 && *ptr2 == '/' && *(ptr2 + 1) == '/') {
/*
行コメント (%// ~)
*/
ptr2 = nextLine(ptr2);
if (EolChr != '\n')
ptr2 = skipNulLine(ptr2);
ptr = *tlhp;
goto LINE_RETRY;
} else if (*ptr2 == *(ptr2 + 1) && strchr("<=>", *ptr2) != NULL) {
/*
一時的な行揃え (%<<, %==, %>>)
*/
if (alignPtr >= *tlhp) {
column += align(ptr, alignPtr, maxColumn - (column - alignColumn), leftMargin, alignMode);
ptr = PTR;
alignPtr = NULL;
}
tempCloseChr = CloseChr;
if (column > 0)
*ptr++ = '\r';
switch (*ptr2) {
case '<': // 左詰め
ptr2 += 2;
if ((column = leftMargin) > 0)
ptr = getIndentStr(ptr, column);
if (*ptr2 == (uchar)(L'━' >> 8) && *(ptr2 + 1) == (uchar)(L'━')) {
*ptr++ = CTRL_CHAR;
*ptr++ = HR_CHAR;
}
break;
case '=': // センタリング
case '>': // 右詰め
alignMode = *ptr2;
ptr2 += 2;
*ptr++ = '\x1b';
*ptr++ = '[';
*ptr++ = (column / 10) + '0';
*ptr++ = (column % 10) + '0';
*ptr++ = 'C';
alignPtr = ptr;
alignColumn = column;
break;
}
continue;
} else if (version > 0) {
/*
ユーザー定義マクロ
*/
uchar *p;
CHK_MACRO:
p = getMacro(macroListHead, ptr2, CloseChr);
ptr2 = PTR2;
if (p == NULL)
continue;
if (tsp <= textStack + 1) {
for (p = "*ERROR: macro"; *ptr++ = *p++;)
;
goto ENCOUNT_EOL0;
}
if (p != NULL) {
ARGS *ap;
if ((ap = malloc(sizeof(ARGS))) == NULL)
goto HEAP_ERROR;
for (n = 0; n < 10; n++)
ap->arg[n] = NULL;
if (*ptr2 == '(' && version >= v3_32) {
ptr2 = expandMacroArg(ap, ptr, ptr2 + 1, f);
if (ptr2 == NULL)
goto HEAP_ERROR;
}
ap->prev = macroArgs;
macroArgs = ap;
if (*ptr2 == CloseChr)
ptr2++;
if (EolChr != '\n')
ptr2 = skipNulLine(ptr2);
(--tsp)->text = ptr2;
tsp->flag = inMACRO;
ptr2 = p;
if (EolChr != '\n')
ptr2 = skipNulLine(ptr2);
wordHead = ptr2;
if (ptr != lineHead)
continue;
ptr = *tlhp;
goto LINE_RETRY;
}
}
} else if (c == RefChr && ctrlChr != '\0' && tsp > textStack + 1) {
c = refVar(ptr2, f);
ptr2 = PTR2;
if (c == 0) {
ctrlChr = '\0';
wordHead = ptr2;
continue;
}
} else if (c == 'T' && ctrlChr != '\0'
&& (strnEqu(ptr2, "YPE=", 4) || strnEqu(ptr2, "ype=", 4))
&& (isalpha(ptr2[4]) && isalpha(ptr2[5]) && isalpha(ptr2[6]))
&& (ptr2[7] == ':' || ptr2[7] == ',' || ptr2[7] == ';')
// && ptr2[8] >= '\x20') {
) {
uchar *head = *tlhp, *p;
if ((*head == CTRL_CHAR || tlhp < lhp0 && *(head = *(tlhp + 1)) == CTRL_CHAR)
&& *(head + 1) == DUMMY_CHAR) {
*(head + 1) = EXEC_CHAR;
if (*ptr2 == 'y') {
/*
'Type='
*/
ptr2 += 4; // skip 'ype='
for (p = ptr; --ptr >= *tlhp;) {
if (*ptr != '\x20' || *ptr != '\t' || *ptr != '\f')
break;
}
ptr++;
*ptr++ = CTRL_CHAR;
*ptr++ = NULTYPE_CHAR;
while ((c = *ptr2++) != '\0' && c != '\n' && c != '\x1a') {
if (c == '\r')
continue;
if (c == RefChr) {
if (ptr + 256 > (uchar *)tlhp)
goto ERROR;
ptr = envSubst(ptr, ptr2, f);
ptr2 = PTR2;
continue;
}
*ptr++ = c;
if (iskanji1(c))
*ptr++ = *ptr2++;
}
*ptr++ = '\0';
bolFlag = TRUE;
goto ENCOUNT_EOL0;
} else {
/*
'TYPE=~' を '<~' に置き換えた上で右揃えする
*/
int n, k;
short m;
uchar *temp;
k = CWIDTH - 2;
if (Width + Lmargin > k)
k = Width + Lmargin;
ptr2 += 4; // skip 'YPE='
for (p = ptr; --ptr >= *tlhp;) { // 先行する空白を取り除く
if (*ptr == '\x20' || *ptr == '\f') {
column--;
continue;
}
if (*ptr == '\t' && *(ptr - 1) == '\t') { // TAB が1個残るのは仕様
column -= 8;
continue;
}
break;
}
ptr++;
temp = ptr + 32;
n = getTypeLine(temp, ptr2, (uchar *)tlhp, f) + 2; // +2...'<' と '>' の分
ptr2 = PTR2;
if (n < 0)
goto ERROR;
if (n > 128)
goto TOO_LONG_TYPE;
if ((n < k || column + n > 128)
&& column + n > k && head == *tlhp) {
*ptr++ = '\0';
*--tlhp = ptr;
if ((void *)ptr > (void *)tlhp)
goto ERROR;
column = 0;
}
if (column + n > 128)
goto TOO_LONG_TYPE;
m = k - n - column;
if (m > 0) {
if (m >= 4) {
*ptr++ = '\x1b';
*ptr++ = '[';
if (m >= 10) { // m < 100 を仮定
*ptr++ = (m / 10) + '0';
m %= 10;
}
*ptr++ = m + '0';
*ptr++ = 'C';
} else {
while (--m >= 0)
*ptr++ = '\f';
}
}
*ptr++ = CTRL_CHAR;
*ptr++ = TYPE_CHAR;
while (*ptr++ = *temp++)
;
bolFlag = TRUE;
goto ENCOUNT_EOL0;
TOO_LONG_TYPE:
*head++ = (uchar)(L'◎' >> 8);
*head = (uchar)(L'◎');
for (p = "*ERROR: TYPE"; *ptr++ = *p++;)
;
bolFlag = TRUE;
goto ENCOUNT_EOL0;
}
}
}
/*
! 制御文字処理は取り敢えずここまで
*/
if (column == (maxColumn - 1) && iskanji(c)) {
--ptr2;
break;
}
*ptr++ = c;
column++;
/* 全角文字処理 ↓ */
if (iskanji1(c)) {
if (*ptr++ = *ptr2++) {
if (iskanji(c))
column++;
} else { // 第2バイトが00の文字は EOF 扱い
ptr -= 2;
column--;
c = '\0';
goto CTRL_RETRY;
}
}
/* 全角文字処理 ↑ */
}
/*
! 一行の処理は取り敢えずここまで
*/
bolFlag = FALSE;
/*
未処理のままの中央揃え/右揃えの後始末
*/
if (alignPtr >= *tlhp) {
column += align(ptr, alignPtr, maxColumn - (column - alignColumn), leftMargin, alignMode);
ptr = PTR;
alignPtr = NULL;
}
/*
語単位の追い込み
*/
if (FillMode < 0 && isalnum(c) && (isalnum(*ptr2) || *ptr2 == '.' || *ptr2 == ',' || *ptr2 == ';')) {
uchar *p = ptr2;
short n;
while (p >= wordHead) {
uchar cc;
cc = *--p;
if (!isalnum(cc)) {
p++;
break;
}
}
if (p > wordHead) {
n = ptr2 - p;
if (n <= Width) {
column -= n;
ptr -= n;
ptr2 -= n;
}
}
}
/*
! 禁足処理(めんどくさいからやめたい)
*/
if (column >= maxColumn - 1 && column <= maxColumn && iskanji(*ptr2)) {
Kinw[0] = ptr2[0];
Kinw[1] = ptr2[1];
if (dinstr(kinsokuChrs, Kinw)) {
*ptr++ = *ptr2++;
*ptr++ = *ptr2++;
column += 2;
}
}
/*
行末の制御文字
*/
for (;;) {
c = *ptr2++;
if (c == '\0' || c == EolChr || c == '\x1a') {
bolFlag = (c == EolChr);
break;
} else if (c == '\x1b') {
int i = isEscSeq(ptr2);
if (i > 0) {
*ptr++ = c;
while (--i >= 0)
*ptr++ = *ptr2++;
if (*(ptr - 1) == 'C' || *(ptr - 1) == 'D') {
column = adjustColumn(column, *(ptr - 1) == 'C');
if (column < maxColumn)
goto CHAR_RETRY;
}
continue;
}
} else if (c == '\b') {
*ptr++ = c;
column--;
if (column < maxColumn)
goto CHAR_RETRY;
continue;
} else if (c == ctrlChr && *ptr2 == *(ptr2 + 1) && strchr("<=>", *ptr2) != NULL) {
goto CTRL_RETRY;
} else if (c < '\x20' && c != '\f' || c == '\x7f') {
continue;
}
ptr2--;
break;
}
if (!WrapFlag) {
ptr2 = nextLine(ptr2);
bolFlag = TRUE;
}
if (FillMode < 0) {
while (*ptr2 == ' ')
ptr2++;
if (*ptr2 == (uchar)(L' ' >> 8) && *(ptr2 + 1) == (uchar)(L' '))
ptr2 += 2;
}
ENCOUNT_EOL:
if (alignPtr >= *tlhp) {
column += align(ptr, alignPtr, maxColumn - (column - alignColumn), leftMargin, alignMode);
ptr = PTR;
alignPtr = NULL;
}
if (cutAlignMode != 0) {
ptr = insertCut(ptr, cutNo, cutLineNo, cutColumn, cutColor);
if (++cutLineNo >= cutLineNoMax) {
cutNo = -1;
cutAlignMode = 0;
}
}
*ptr++ = '\0';
ENCOUNT_EOL0:
/*
CUT '?' フラグの処理
*/
if (cutNo >= 0 && (cut[cutNo].flag & cutDUP)) {
int n;
cut[cutNo].flag &= ~cutDUP;
if ((n = dinstr(*tlhp, cutID)) > 0) {
n += 4 - 1;
while (cutLineNo < cutLineNoMax) {
uchar *p = *tlhp;
*--tlhp = ptr;
if ((void *)ptr > (void *)tlhp)
goto ERROR;
while (*ptr++ = *p++)
;
*(*tlhp + n) = cutLineNo++;
}
}
cutNo = -1;
}
if ((*ptr2 == '\0' || *ptr2 == '\x1a') && tsp->text == NULL)
break;
if (fontSize > 0 && EolChr != '\n')
lineSpace++;
while (--lineSpace >= 0) {
if (cutAlignMode != 0) {
*--tlhp = ptr;
if (boxStr[0] != '\0')
ptr = stpcpy(ptr, boxStr);
ptr = insertCut(ptr, cutNo, cutLineNo, cutColumn, cutColor);
if (++cutLineNo >= cutLineNoMax) {
if (Lspace > 0)
cutBottomSpace = cutAlignMode;
cutNo = -1;
cutAlignMode = 0;
}
*ptr++ = '\0';
} else {
if (boxStr[0] != '\0') {
*--tlhp = ptr;
ptr = stpcpy(ptr, boxStr);
*ptr++ = '\0';
} else {
*--tlhp = ptr - 1;
}
tempIndent = -128;
cutBottomSpace = 0;
}
if ((void *)ptr > (void *)tlhp)
goto ERROR;
}
CHK_TAIL:
if (EolChr != '\n')
ptr2 = skipNulLine(ptr2);
if (fontSize != 0 && *ptr2 == CloseChr) {
fontSize = 0;
ptr2++;
goto CHK_TAIL;
}
}
/*
! 一番でかいループおわり
*/
ENCOUNT_EOF:
if ((void *)ptr > (void *)tlhp) {
goto ERROR; /* 行ポインタテーブルをつぶしてしまった… */
} else {
int nLine;
while (cutAlignMode != 0) {
*--tlhp = ptr;
if ((void *)ptr > (void *)tlhp)
goto ERROR;
ptr = insertCut(ptr, cutNo, cutLineNo, cutColumn, cutColor);
if (++cutLineNo >= cutLineNoMax) {
cutNo = -1;
cutAlignMode = 0;
}
*ptr++ = '\0';
}
/*
0行、または、24ドット文字行で終わるファイルは空行を補う
*/
nLine = LINENO;
if (nLine == 0 || dinstr(*tlhp, LARGE_IDSTR) > 0) {
*--tlhp = ptr;
*ptr++ = '\0';
nLine++;
if ((void *)ptr > (void *)tlhp)
goto ERROR;
}
lpmx = nLine;
lhp = (uchar **)(((int)ptr + 3) & -4);
/*
行ポインタテーブルを移動し、その末尾アドレスを返す
*/
lhp0 = moveLhp(lhp, tlhp, nLine);
goto RETURN;
}
HEAP_ERROR:
d_heap();
ERROR:
w_open();
w_mes(0, "テキストの展開に失敗しました");
w_wait(0);
lhp0 = NULL;
RETURN:
while (f->last != NULL) {
FORM *ff = f->last;
free(f);
f = ff;
}
while (macroListHead != NULL) {
MACRO *mp = macroListHead;
macroListHead = mp->next;
free(mp);
}
if (kinsokuChrs != defKinsokuChrs)
free(kinsokuChrs);
while (varListHead != NULL) {
VAR *vp = varListHead;
varListHead = vp->next;
free(vp->contents);
free(vp);
}
while (macroArgs != NULL)
freeMacroArg();
return lhp0;
}
/*
24ドット処理の文字列の表示幅調整
ptr 調整後のポインタ
ptr2 調整するポインタ
column 現在桁
maxColumn 画面桁幅
cont_flag 処理中に最大桁を越えたらTRUE (次行も24ドット表示)
戻り値 更新後のcolumn
*/
static int
sort_job24(uchar *ptr, uchar *ptr2, short column, short maxColumn, const FORM *f, uchar *contFlag)
{
if (*ptr2 == CloseChr) {
PTR = ptr;
PTR2 = ++ptr2;
return column;
}
*ptr++ = CTRL_CHAR;
*ptr++ = LARGE_CHAR;
*ptr++ = column + NUM_BIAS;
*ptr++ = (curColor & 3) + NUM_BIAS;
maxColumn = (maxColumn + maxColumn) - 3;
column += column; // 4ドット単位
column = sort_job_12_24(ptr, ptr2, column, maxColumn, f, contFlag, FALSE, CloseChr2);
return (column + 2 - 1) >> 1;
}
/*
12ドット処理の文字列の表示幅調整
*/
static int
sort_job12(uchar *ptr, uchar *ptr2, short column, short maxColumn, const FORM *f, uchar *contFlag)
{
if (*ptr2 == CloseChr) {
PTR = ptr;
PTR2 = ++ptr2;
return column;
}
*ptr++ = CTRL_CHAR;
*ptr++ = SMALL_CHAR;
maxColumn = (maxColumn << 2) - 3;
column <<= 2; // 2ドット単位
column = sort_job_12_24(ptr, ptr2, column, maxColumn, f, contFlag, TRUE, '\0');
return (column + 4 - 1) >> 2;
}
/*
12/24 ドット処理本体
*/
static int
sort_job_12_24(uchar *ptr, uchar *ptr2, short column, short maxColumn,
const FORM *f, uchar *contFlag, uchar kinsokuFlag, uchar closeChr2)
{
uchar c, c2;
uchar refChr;
refChr = RefChr;
if (tsp->flag < 0)
refChr = '\0';
for (;;) {
c = *ptr2++;
retry:
if (c == '\0' || c == '\x1a') {
if (tsp->text != NULL) {
if (tsp->flag & inMACRO)
freeMacroArg();
ptr2 = tsp->text;
tsp++;
refChr = RefChr;
continue;
}
break;
}
if (c == EolChr || c == CloseChr || c == closeChr2)
break;
if (c == '\t') {
short n;
if (column > maxColumn) {
ptr2--;
break;
}
n = column;
column += TabWidth * 3;
column -= (column % (TabWidth * 3));
for (n = (column - n) / 3; --n >= 0;)
*ptr++ = ' ';
continue;
} else if (c == '\x1b') {
int n = isEscSeq(ptr2);
if (n > 0 && *(ptr2 + n - 1) == 'm') {
*ptr++ = c; // ESC
while (--n >= 0)
*ptr++ = *ptr2++;
continue;
}
} else if (c == EscChr) {
c = getEscSeq(ptr2);
ptr2 = PTR2;
if (iscntrl(c))
goto retry;
} else if (iscntrl(c)) {
continue;
} else if (c == refChr && tsp > textStack + 1) {
c = refVar(ptr2, f);
ptr2 = PTR2;
if (c == 0) {
refChr = '\0';
continue;
}
}
if (column > maxColumn) {
ptr2--;
break;
}
if (iskanji1(c)) {
c2 = *ptr2++;
if (c2 == '\0')
continue;
if (iskanji(c)) {
if (column > maxColumn - 3) {
ptr2 -= 2;
break;
}
column += 6;
} else {
column += 3;
}
*ptr++ = c;
*ptr++ = c2;
} else {
*ptr++ = c;
column += 3;
}
}
if (c == '\0' || c == '\x1a' || c == closeChr2)
ptr2--;
else if (c != CloseChr) {
*contFlag = TRUE;
if (c == EolChr) {
(*contFlag)++;
} else if (!WrapFlag) {
static uchar term[] = "\x18\n\x1a";
(*contFlag)++;
term[0] = CloseChr;
ptr2 += strcspn(ptr2, term);
if (*ptr2 == CloseChr) {
*contFlag = FALSE;
ptr2 += strcspn(ptr2, term + 1);
}
} else if (kinsokuFlag && iskanji(*ptr2)) {
Kinw[0] = ptr2[0];
Kinw[1] = ptr2[1];
if (dinstr(kinsokuChrs, Kinw)) {
*ptr++ = *ptr2++;
*ptr++ = *ptr2++;
column += 6;
if (*ptr2 == CloseChr) {
*contFlag = FALSE;
ptr2++;
}
}
}
}
*ptr++ = NORM_CHAR;
PTR = ptr;
PTR2 = ptr2;
return column;
}
/*
逆順に生成した行ポインタテーブルを正順に並べ替えつつ移動する
どさくさに sort() の後始末
*/
static uchar **
moveLhp(uchar **lhp, uchar **tlhp, int n)
{
uchar **p, **q, *t;
/*
その場で正順に並べ替える
*/
p = tlhp;
q = p + n;
while (p < q) {
t = *--q;
*q = *p;
*p++ = t;
}
/*
整理済みテキスト直後に移動する
ついでに、'◎' の内部コードが残っていたら、対になる 'TYPE=' がないので元に戻す
*/
while (--n >= 0) {
*lhp++ = t = *tlhp++;
if (*t++ == CTRL_CHAR && *t == DUMMY_CHAR) {
*t = (uchar)(L'◎');
*--t = (uchar)(L'◎' >> 8);
}
}
return lhp;
}
/*
'TYPE=' 以降を簡易処理 (コントロールコード類の削除) して
作業バッファにコピーしつつ、その画面上での桁幅を返す
*/
static int
getTypeLine(uchar *buff, uchar *p, uchar *bound, const FORM *f)
{
int n = 0, m;
uchar *q = buff;
uchar c;
while ((c = *p++) != '\0' && c != '\n' && c != '\x1a') {
if (c == '\x1b' && (m = isEscSeq(p))) {
n += m + 1;
*q++ = c;
while (--m >= 0)
*q++ = *p++;
}
if (iscntrl(c))
continue;
if (c == RefChr) {
if (q + 256 > bound)
return -1;
q = envSubst(q, p, f); // 本当はこの中の2バイト半角も真面目に数えるべきだが省略
p = PTR2;
continue;
}
*q++ = c;
if (iskanji1(c)) {
*q++ = *p++;
if (!iskanji(c))
n++;
}
}
*q = '\0';
if (c != '\n')
p--;
PTR2 = p;
return (q - buff) - n;
}
/*
%menu~%endmenu 内のメニュー行の処理
*/
static int
getMenuLine(uchar *buff, uchar *p, uchar *bound, const FORM *f)
{
uchar *q = buff;
uchar c;
int n;
*q++ = FALSE; // 仮に実行可能フラグ OFF
while ((c = *p++) != '\0' && c != '\n' && c != '\x1a') {
if (iscntrl(c))
continue;
if (c == RefChr) {
if (q + 256 > bound)
return -1;
q = envSubst(q, p, f);
p = PTR2;
continue;
}
*q++ = c;
if (iskanji1(c))
*q++ = *p++;
}
*q++ = '\0';
if (c != '\n')
p--;
PTR2 = p;
n = dinstr(buff + 1, "TYPE=");
if (n > 0) {
*buff = TRUE;
q = buff + n;
p = q + 5;
// メニュー項目文字列とTYPE=の間の空白を削る (0x8020 なんかがあるとコケる)
while (--q >= buff + 1 && (*q == ' ' || *q == '\t'))
;
q++;
*q++ = '\0';
while ((*q++ = *p++) != '\0')
;
}
PTR = q;
return 0;
}
/*
シェル変数/環境変数内容の取得
*/
static uchar *
getSysVar(uchar *name)
{
SHELLVAR *vp;
uchar *p = NULL;
for (vp = sysVarListHead; vp != NULL; vp = vp->next) {
if (strEqu(name, vp->name)) {
p = vp->name;
while (*p++)
;
break;
}
}
if (vp == NULL)
p = getenv(name);
return p;
}
static uchar *
copySysVar(uchar *name, uchar *buff)
{
VAR *vp;
uchar *p;
vp = getVar(name);
if (vp == NULL)
return buff;
p = vp->contents;
while (*buff++ = *p++)
;
return --buff;
}
/*
TYPE=~ 中の変数置換
*/
static uchar *
envSubst(uchar *p, uchar *name, const FORM *f)
{
uchar *q, c;
PTR2 = q = name;
while ((c = *q++) != '\0' && c != CloseChr && c > '\x20') {
if (iskanji1(c))
q++;
}
if (c != CloseChr || q - name >= 256) {
*p++ = RefChr;
} else {
if (q - name > 1) {
*(q - 1) = '\0';
p = copySysVar(name, p);
*(q - 1) = c;
} else {
*p++ = RefChr;
}
PTR2 = q;
}
return p;
}
/*
右詰めとセンタリング (先頭桁位置の調整)
*/
static int
align(uchar *tail, uchar *p, short column, short lmargin, uchar alignMode)
{
short d;
int n;
*tail = '\0';
PTR = tail;
if (tail == p) {
strcpy(p - 5, p); // ESC[00C を削除
PTR -= 5;
return 0;
}
column -= lmargin;
if (alignMode == '=')
column /= 2;
column += lmargin;
if (column < 0)
column = 0;
--p;
d = *--p - '0';
d += (*--p - '0') * 10;
d = column - d;
if (column == 0) {
p -= 2;
strcpy(p, p + 5); // ESC[00C を削除
PTR -= 5;
} else {
*p++ = (column / 10) + '0';
*p++ = (column % 10) + '0';
}
while (n = dinstrchr(p, CTRL_CHAR)) {
p += n;
switch (*p) {
case LARGE_CHAR:
*(p + 1) += d;
break;
case CUT_CHAR:
*(p + 4) += d;
break;
}
}
return d;
}
/*
ESC[~C, ESC[~D 後のカラム位置調整
*/
static short
adjustColumn(short column, uchar forwardFlag)
{
int n;
extern uchar escNumBuff[];
n = atoi(escNumBuff);
if (n == 0)
n++;
if (forwardFlag)
column += n;
else if (column >= n)
column -= n;
else
column = 0;
return column;
}
/*
インデント付け用桁送り文字列を得る
*/
static uchar *
getIndentStr(uchar *p, short n)
{
const uchar *indentStrTable[] = {
"", "\f", "\f\f", "\f\f\f", "\f\f\f\f", "\t\b\b\b", "\t\b\b", "\t\b", "\t",
};
if (n <= 8)
p = stpcpy(p, indentStrTable[n]);
else if (n == 16)
p = stpcpy(p, "\t\t");
else if (n == 24)
p = stpcpy(p, "\t\t\t");
else
p += sprintf(p, "\x1b[%dC", n);
return p;
}
/*
引用表現された文字の取得
*/
static uchar
getEscSeq(uchar *p)
{
uchar c;
while ((c = *p++) == '\r')
;
switch (c) {
case '\0':
PTR2 = p - 1;
return c;
case 'a':
c = '\a'; break;
case 'b':
c = '\b'; break;
case 'e':
c = '\x1b'; break;
case 'f':
c = '\f'; break;
case 'n':
c = '\n'; break;
case 'r':
c = '\r'; break;
case 't':
c = '\t'; break;
case 'v':
c = '\v'; break;
case 'x':
if (isxdigit(*p) && isxdigit(*(p + 1))) {
uchar cc;
c = (*p++ | 0x20) - '0';
if (c >= 10)
c -= 'a' - '0' - 10;
cc = (*p++ | 0x20) - '0';
if (cc >= 10)
cc -= 'a' - '0' - 10;
c = (c << 4) + cc;
}
break;
case '0':
case '1':
if (isodigit(*p) && isodigit(*(p + 1))) {
c = c - '0';
c = (c << 3) | (*p++ - '0');
c = (c << 3) | (*p++ - '0');
}
break;
}
PTR2 = p;
return c;
}
/*
書式指定コマンド番号の取得
*/
static int
getCommand(uchar *p, uchar headFlag)
{
int i;
PTR2 = p;
for (i = 1; i < NCMDS; i++) {
int n;
if (version < commandTable[i].version)
continue;
n = strlen(commandTable[i].name);
if (strnEqu(p, commandTable[i].name, n) && p[n] <= '\x20') {
uchar c;
if (!headFlag && (commandTable[i].flag & cfBREAK)) {
PTR2--;
return RETRY_CMD;
}
p += n;
while ((c = *p++) == ' ' || c == '\t' || c == '\r')
;
PTR2 = --p;
return i;
}
}
return -1;
}
/*
10進数値を得る
*/
static short
getNum(uchar *p, short n)
{
uchar c;
p = skipBlank(p);
if (*p == '+')
n += atoi(++p);
else if (*p == '-')
n -= atoi(++p);
else
n = atoi(p);
while ((c = *p++) == '+' || c == '-')
;
p--;
while ((c = *p++) >= '0' && c <= '9')
;
PTR2 = --p;
return n;
}
static short
getNum2(uchar *p, short n, short defVal, short baseVal)
{
if (*p == '*') {
p = skipBlank(p + 1);
if ((n = defVal) < 0)
n = baseVal;
if (*p != '+' && *p != '-') {
PTR2 = p;
return n;
}
}
return getNum(p, n);
}
/*
色コードを得る
*/
static ushort
getRGB(uchar *p, ushort defColor)
{
p = skipBlank(p);
if (*p++ == '(') {
uchar c[3];
short i;
for (i = 0; i < 3; i++) {
int n;
p = skipBlank(p);
if (*p < '0' || *p > '9')
break;
n = atoi(p);
if (n < 0 || n > 31)
break;
c[i] = n;
p += strspn(p, "0123456789");
p = skipBlank(p);
if (i < 2 && *p++ != ',')
break;
}
if (i == 3 && *p++ == ')')
return (c[0] << 6) | (c[1] << 11) | (c[2] << 1);
}
return defColor;
}
/*
%h-rule
*/
static short
getHRuleChar(uchar *buff, uchar **pp)
{
uchar *p = *pp;
uchar c;
short n = 1;
c = *p++;
buff[0] = c;
buff[1] = '\0';
if (iskanji1(c)) {
buff[1] = *p++;
if (iskanji(c))
n++;
}
*pp = p;
return n;
}
static uchar *
getHRule(uchar *p, uchar *p2, short n)
{
uchar ch1[2], ch2[2], ch3[2];
short l1, l2, l3;
if (n <= 0)
return p;
if (iscntrl(*p2) || *p2 == ' ') {
ch1[0] = (uchar)(L'━' >> 8);
ch1[1] = (uchar)(L'━');
l1 = 2;
} else
l1 = getHRuleChar(ch1, &p2);
if (l1 > n)
return p;
if (iscntrl(*p2)) {
ch2[0] = ch1[0];
ch2[1] = ch1[1];
ch3[0] = ch1[0];
ch3[1] = ch1[1];
l2 = l3 = l1;
} else {
l2 = getHRuleChar(ch2, &p2);
if (iscntrl(*p2))
l3 = 0;
else
l3 = getHRuleChar(ch3, &p2);
}
if (l3 == 0) {
while (n >= l1) {
*p++ = ch1[0];
if ((*p++ = ch1[1]) == '\0')
p--;
n -= l1 + l2;
if (n < 0)
break;
*p++ = ch2[0];
if ((*p++ = ch2[1]) == '\0')
p--;
}
} else {
*p++ = ch1[0];
if ((*p++ = ch1[1]) == '\0')
p--;
n -= l1;
while (n >= l2 + l3) {
*p++ = ch2[0];
if ((*p++ = ch2[1]) == '\0')
p--;
n -= l2;
}
*p++ = ch3[0];
if ((*p++ = ch3[1]) == '\0')
p--;
}
return p;
}
/*
マクロの定義内容を得る
*/
static uchar *
getMacro(MACRO *mp, uchar *p, uchar closeChr)
{
PTR2 = p;
while (mp != NULL) {
int n = strlen(mp->name);
if (strnEqu(p, mp->name, n) && (p[n] <= 0x20 || p[n] == closeChr || p[n] == '(')) {
PTR2 = p + n;
return mp->contents;
}
mp = mp->next;
}
return NULL;
}
static int
setSysVar(const uchar *name, const uchar *contents)
{
SHELLVAR *vp;
int n = strlen(name) + 1;
vp = malloc(sizeof(SHELLVAR) + n + strlen(contents) + 1);
if (vp == NULL)
return -1;
strcpy(vp->name, name);
strcpy(vp->name + n, contents);
vp->next = sysVarListHead;
sysVarListHead = vp;
return 0;
}
/*
変数の定義内容を得る
*/
static VAR *
getVar(const uchar *name)
{
VAR *vp;
uchar *p;
if (*(name + 1) == '\0' && isdigit(*name)) {
if (macroArgs == NULL)
return NULL;
else
return macroArgs->arg[*name - '0'];
}
for (vp = varListHead; vp != NULL; vp = vp->next) {
if (strEqu(name, vp->name))
return vp;
}
p = getSysVar(name);
if (p != NULL && (p = strdup(p)) != NULL) {
vp = malloc(sizeof(VAR) + strlen(name) + 1);
vp->contents = p;
strcpy(vp->name, name);
vp->next = varListHead;
varListHead = vp;
return vp;
}
return NULL;
}
static int
setVar(const uchar *name, const uchar *contents)
{
VAR *vp;
vp = getVar(name);
if (vp == NULL) {
vp = malloc(sizeof(VAR) + strlen(name) + 1);
strcpy(vp->name, name);
vp->next = varListHead;
varListHead = vp;
} else {
free(vp->contents);
}
vp->contents = strdup(contents);
if (vp->contents == NULL)
return -1;
return 0;
}
static int
incVar(const uchar *name)
{
static const ushort rangeTable[][3] = {
{ '0', '1', '9', },
{ 'A', 'A', 'Z', },
{ 'a', 'a', 'z', },
{ L'0', L'1', L'9', },
{ L'A', L'A', L'Z', },
{ L'a', L'a', L'z', },
{ L'Α', L'Α', L'Ω', },
{ L'α', L'α', L'ω', },
};
static const uchar zenHira[] =
"あいうえおかきくけこさしすせそたちつてとなにぬねの"
"はひふへほまみむめもやゆよらりるれろわをん";
static const uchar zenKata[] =
"アイウエオカキクケコサシスセソタチツテトナニヌネノ"
"ハヒフヘホマミムメモヤユヨラリルレロワヲン";
static const uchar hanKata[] =
"アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワヲン";
VAR *vp;
uchar c, *p;
ushort lastChr;
short n;
vp = getVar(name);
if (vp == NULL) {
if ((vp = malloc(sizeof(VAR) + strlen(name) + 1)) == NULL)
return -1;
strcpy(vp->name, name);
vp->next = varListHead;
varListHead = vp;
if ((vp->contents = strdup("1")) == NULL)
return -1;
return 0;
}
lastChr = '\0';
p = vp->contents;
while ((c = *p++) != '\0') {
if (iskanji1(c))
lastChr = (c << 8) | *p++;
else
lastChr = c;
}
p--;
#define head (rangeTable[n][0])
#define head2 (rangeTable[n][1])
#define tail (rangeTable[n][2])
for (n = 0; n < sizeof(rangeTable) / sizeof(rangeTable[0]); n++) {
if (lastChr >= head && lastChr <= tail)
break;
}
if (n >= sizeof(rangeTable) / sizeof(rangeTable[0])) {
if (lastChr < 0x0100) {
if ((n = dinstrchr(hanKata, *--p)) > 0) {
if (hanKata[n] != '\0')
*p = hanKata[n];
}
} else {
uchar *q;
p -= 2;
if ((n = dinstr(q = zenHira, p)) > 0
|| (n = dinstr(q = zenKata, p)) > 0) {
q += n + 2 - 1;
if (*q != '\0') {
*p++ = *q++;
*p = *q;
}
}
}
return 0;
}
if (head < 0x100) {
if (++(*--p) <= tail)
return 0;
*p = head;
while (--p >= vp->contents) {
if (*p == ' ') {
*p = head2;
return 0;
}
if (*p < head || *p > tail)
return 0;
if ((*p)++ <= tail)
return 0;
}
p = malloc(strlen(vp->contents) + 2);
if (p == NULL)
return -1;
strcpy(p + 1, vp->contents);
free(vp->contents);
vp->contents = p;
*p++ = head2;
} else {
uchar highByte = (head >> 8);
if (++(*--p) <= (uchar)tail)
return 0;
*p = head;
p--;
while ((p -= 2) >= vp->contents) {
if (*p == ' ' && *(p + 1) == ' '
|| *p == (uchar)(L' '>>8) && *(p + 1) == (uchar)L' ') {
*p++ = highByte;
*p = head2;
return 0;
}
if (*p != highByte || *(p + 1) < (uchar)head || *(p + 1) > (uchar)tail)
return 0;
if ((*(p + 1))++ <= (uchar)tail)
return 0;
}
if (p + 2 != vp->contents)
return 0;
p = malloc(strlen(vp->contents) + 3);
if (p == NULL)
return -1;
strcpy(p + 2, vp->contents);
free(vp->contents);
vp->contents = p;
*p++ = highByte;
*p = head2;
}
return 0;
#undef head
#undef head2
#undef tail
}
static uchar
refVar(uchar *p, const FORM *f)
{
uchar *name = p, c;
VAR *vp;
while ((c = *p++) != '\0' && c != CloseChr && c > '\x20')
;
if (c != CloseChr) {
p = name;
c = RefChr;
} else {
*--p = '\0';
vp = getVar(name);
*p++ = c;
if (EolChr != '\n')
p = skipNulLine(p);
if (vp != NULL && *vp->contents != '\0') {
(--tsp)->text = p;
tsp->flag = inCONST;
p = vp->contents;
}
c = '\0';
}
PTR2 = p;
return c;
}
static uchar *
expandCommand(uchar *temp, uchar *q, const FORM *f, uchar argFlag)
{
uchar c;
uchar quoteChr = '\0';
while ((c = *q++) != '\0' && c != '\r' && c != '\n' && c != '\x1a') {
if (c == quoteChr) {
quoteChr = '\0';
continue;
}
if (quoteChr == '\0') {
if (c == '\'' || c == '\"') {
quoteChr = c;
continue;
}
if (c == RefChr) {
uchar *qq = q;
VAR *vp;
while ((c = *q++) != '\0' && c != CloseChr && c > '\x20')
;
*--q = '\0';
vp = getVar(qq);
if ((*q = c) == CloseChr)
q++;
if (vp != NULL) {
for (qq = vp->contents; (*temp++ = *qq++) != '\0';)
;
temp--;
}
continue;
}
if (argFlag && (c == ' ' || c == '\t' || c == ',' || c == ')')) {
if (c == ')')
q--;
*temp = '\0';
return q;
}
if ((argFlag || version >= v3_32) && c == EscChr) {
c = getEscSeq(q);
q = PTR2;
if (iscntrl(c) && c != '\t' && c != '\f' && c != '\b' && c != '\r' && c != '\x1b')
continue;
}
}
if (iskanji1(c)) {
*temp++ = c;
*temp++ = *q++;
} else
*temp++ = c;
}
*temp = '\0';
q--;
if (!argFlag) {
q = nextLine(q);
if (EolChr != '\n')
q = skipNulLine(q);
}
return q;
}
uchar *
expandMacroArg(ARGS *ap, uchar *temp, uchar *q, const FORM *f)
{
VAR *vp;
int n;
uchar c;
for (n = 0; n < 10; n++) {
while ((c = *q++) == ' ' || c == '\t' || c == '\r')
;
if (c == ')')
return q;
q--;
if (c == '\n')
return q;
q = expandCommand(temp, q, f, TRUE);
if ((vp = malloc(sizeof(VAR))) == NULL)
return NULL;
vp->next = NULL;
if ((vp->contents = strdup(temp)) == NULL)
return NULL;
ap->arg[n] = vp;
}
while ((c = *q++) == ' ' || c == '\t' || c == '\r')
;
if (c == ')')
return q;
else
return --q;
}
static void
freeMacroArg(void)
{
ARGS *ap;
VAR *vp;
int n;
if ((ap = macroArgs) == NULL)
return;
macroArgs = ap->prev;
for (n = 0; n < 10; n++) {
if ((vp = ap->arg[n]) == NULL)
break;
free(vp->contents);
free(vp);
}
free(ap);
}
static int
skipIfBlock(const uchar *p, uchar ctrlChr, uchar elseFlag)
{
for (;;) {
if (*p == '\0' || *p == '\x1a')
break;
if (*p++ == ctrlChr) {
switch (getCommand(p, TRUE)) {
case IF_CMD:
skipIfBlock(nextLine(p), ctrlChr, FALSE);
p = PTR2;
break;
case ELIF_CMD:
if (elseFlag)
return TRUE;
break;
case ELSE_CMD:
if (!elseFlag)
break;
/* NOBREAK */
case ENDIF_CMD:
PTR2 = nextLine(p);
return FALSE;
}
p = nextLine(p);
}
}
PTR2 = p;
return FALSE;
}
static uchar *
insertCut(uchar *p, short cutNo, uchar cutLineNo, uchar cutColumn, uchar cutColor)
{
if (cutColor != curColor)
p = setColor(p, cutColor);
*p++ = CTRL_CHAR;
*p++ = CUT_CHAR;
*p++ = (cutNo >> 6) + NUM_BIAS;
*p++ = (cutNo & (64 - 1)) + NUM_BIAS;
*p++ = cutLineNo;
*p++ = cutColumn + NUM_BIAS;
return p;
}
static uchar *
setColor(uchar *p, uchar color)
{
*p++ = '\x1b';
*p++ = '[';
if (color < 8)
*p++ = '3';
else
*p++ = '4';
*p++ = (color & 7) + '0';
*p++ = 'm';
return p;
}